package RFID;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;


//udp传输： 接收
/**步骤：---
 * 1、建立udp socket，设置接收端口
 * 2、预先创建数据存放的位置，封装
 * 3、使用receive阻塞式接收
 * 4、关闭资源
 * https://blog.csdn.net/zhangjin7422/article/details/107077687/
 * */

public class ReaderDemo {
    public static void main(String[] args) throws Exception{
        String MyIpAdd=getIP();
        InetAddress Addip=InetAddress.getByName(MyIpAdd) ;

        DatagramSocket s = new DatagramSocket(22347,Addip);        /** 1、建立udp socket端点 */
        System.out.println("当前软件绑定的IP："+MyIpAdd+":22347\n\n");

        String SendInfStr="a6";
        byte[] SendBuf = new byte[1];                                   /** 2、提供发送数据，封装打包 a6 为搜索在线设备的指令 */
        SendBuf[0]=(byte)0xa6;
        DatagramPacket dp = new DatagramPacket(SendBuf, SendBuf.length, InetAddress.getByName("255.255.255.255"), 39169);
        try {
            s.send(dp);
            System.out.println("SendTo ip::255.255.255.255\nport::39169\ndata::"+SendInfStr);
            System.out.println("电脑发送搜索在线设备的指令"+"\n\n");
        } catch (IOException e) {
            System.out.println("发送失败： ");
            e.printStackTrace();
        }

        byte [] readcardbuf= new byte[1000];             /** ic卡扇区内数据*/
        byte [] LastBuf =new byte[9];                    /** 用于保存最后上传的信息*/

        boolean i=true;
        while(i){
            int p=0;
            int j=0;
            int m=0;

            byte [] bbuf = new byte [1024];             /**3、预先创建接收数据存放的位置，封装*/
            DatagramPacket rdp = new DatagramPacket(bbuf,bbuf.length);
            s.receive(rdp);                             /**4、使用receive阻塞式接收*/

            String RemoteHostIP=rdp.getAddress().getHostAddress();   /*数据来源IP */
            int RemotePort=rdp.getPort();                            /*数据来源端口*/

            int length =  rdp.getLength();
            byte[] data=  rdp.getData();

            String ReceiveDataStr="";
            String bytestr="";
            String CardNo16="";
            String SerialNum="";
            String CardNoStr="";
            String CardInfStr="";
            long cardno10;
            long cardnum;

            for(p=0;p<length;p++){
                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                ReceiveDataStr=ReceiveDataStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
            }
            System.out.println("From ip::"+rdp.getAddress().getHostAddress()+"\nport::"+rdp.getPort()+"\ndata::"+ReceiveDataStr);

            if(length>=8){        //判断是否是重复上传的数据包
                if(data[0]==LastBuf[0] && data[1]==LastBuf[1] && data[2]==LastBuf[2] && data[3]==LastBuf[3] && data[4]==LastBuf[4] && data[5]==LastBuf[5] && data[6]==LastBuf[6] && data[7]==LastBuf[7] && data[8]==LastBuf[8]){
                    DisableSendAge(s,data,length,RemoteHostIP,RemotePort);         //向读卡器发确认信息，否则读卡器会连续发三次
                    System.out.println("\n\n");                                  // 重复的上传的数据不分析处理，直接丢弃
                }else{
                    for(p=0;p<9;p++){
                        LastBuf[p]=data[p];   /*将当前接收到的数据保存，用于再次接收到数据时比对*/
                    }

                    switch(data[0]){
                        case (byte)0xf2:
                            System.out.println("在线读卡器响应搜索指令");
                            System.out.println("指令码      ："+Integer.toHexString(data[0] & 0xff));
                            System.out.println("设备IP      ："+Integer.toString(data[1] & 0xff)+"."+Integer.toString(data[2] & 0xff)+"."+Integer.toString(data[3] & 0xff)+"."+Integer.toString(data[4] & 0xff));
                            System.out.println("掩  码      ："+Integer.toString(data[5] & 0xff)+"."+Integer.toString(data[6] & 0xff)+"."+Integer.toString(data[7] & 0xff)+"."+Integer.toString(data[8] & 0xff));
                            System.out.println("端口号      ："+Integer.toString((data[9] & 0xff)+((data[10] & 0xff) *256)));
                            System.out.println("机  号      ："+Integer.toString((data[11] & 0xff)+((data[12] & 0xff) *256)));
                            System.out.println("网  关      ："+Integer.toString(data[13] & 0xff)+"."+Integer.toString(data[14] & 0xff)+"."+Integer.toString(data[15] & 0xff)+"."+Integer.toString(data[16] & 0xff));
                            for(p=17;p<23;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                SerialNum=SerialNum+ bytestr.substring(bytestr.length() -2,bytestr.length());
                                if(p<22){SerialNum=SerialNum+"-";}
                            }
                            System.out.println("网关MAC     ："+SerialNum);
                            String ServerIp=Integer.toString(data[23] & 0xff)+"."+Integer.toString(data[24] & 0xff)+"."+Integer.toString(data[25] & 0xff)+"."+Integer.toString(data[26] & 0xff);
                            System.out.println("远程服务器IP："+ServerIp);
                            //System.out.println("远程服务器IP："+Integer.toString(data[23] & 0xff)+"."+Integer.toString(data[24] & 0xff)+"."+Integer.toString(data[25] & 0xff)+"."+Integer.toString(data[26] & 0xff));
                            SerialNum="";
                            for(p=27;p<33;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                SerialNum=SerialNum+ bytestr.substring(bytestr.length() -2,bytestr.length());
                                if(p<32){SerialNum=SerialNum+"-";}
                            }
                            System.out.println("服务器MAC   ："+SerialNum);
                            System.out.println("网络标识    ："+Integer.toHexString(data[33] & 0xff));
                            System.out.println("响声标识    ："+Integer.toHexString(data[34] & 0xff));
                            SerialNum="";
                            String DeviceMAC="16-88-";
                            for(p=35;p<39;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                DeviceMAC=DeviceMAC+ bytestr.substring(bytestr.length() -2,bytestr.length());
                                SerialNum=SerialNum +Integer.toString(data[p] & 0xff);
                                if(p<38){
                                    SerialNum=SerialNum+"-";
                                    DeviceMAC=DeviceMAC+"-";
                                }
                            }
                            System.out.println("通讯模块序号："+SerialNum);
                            System.out.println("设备MAC地址 ："+DeviceMAC);

                            if(length>39){
                                SerialNum="";
                                for(p=39;p<length;p++){
                                    bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                    SerialNum=SerialNum+ bytestr.substring(bytestr.length() -2,bytestr.length());
                                }
                                System.out.println("设备唯一序号："+SerialNum);
                            }
                            if(ServerIp.compareTo("255.255.255.255")!=0 && ServerIp.compareTo(MyIpAdd)!=0 ){
                                System.out.println("读卡器的远程服务器IP未指向本设备，需将读卡器的远程服务器IP设为:"+MyIpAdd+"\n\n");
                                //SetNetworkPara(s,data,length,RemoteHostIP,RemotePort);                                          //如果需要修改读卡器的IP 掩码 网关 远程服务器IP 通讯端口，取消注释，按网络环境设定正确的值
                            }
                            System.out.println("\n\n");
                            break;
                        case (byte)0xf3:
                            System.out.println("接收到的信息为心跳数据包");
                            System.out.println("指令码："+Integer.toHexString(data[0] & 0xff));
                            System.out.println("设备IP："+Integer.toString(data[1] & 0xff)+"."+Integer.toString(data[2] & 0xff)+"."+Integer.toString(data[3] & 0xff)+"."+Integer.toString(data[4] & 0xff));
                            System.out.println("机器号："+Integer.toString((data[5] & 0xff)+((data[6] & 0xff) *256)));
                            System.out.println("包序号："+Integer.toString((data[7] & 0xff)+((data[8] & 0xff) *256)));
                            System.out.println("心跳码："+Integer.toHexString(data[9] & 0xff));
                            System.out.println("长  度："+Integer.toHexString(data[10] & 0xff));
                            System.out.println("继电器："+Integer.toHexString(data[11] & 0xff));
                            System.out.println("按键值："+Integer.toHexString(data[12] & 0xff));
                            for(p=13;p<17;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                SerialNum=SerialNum+ bytestr.substring(bytestr.length() -2,bytestr.length());
                            }
                            System.out.println("随机码："+SerialNum);
                            SerialNum="";
                            for(p=17;p<length;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                SerialNum=SerialNum+ bytestr.substring(bytestr.length() -2,bytestr.length());
                            }
                            System.out.println("设备序列号："+SerialNum+"\n\n");

                            break;
                        case (byte)0xf8:

                            break;
                        case (byte)0xc1:         /*接收到的信息为IC只读上传的IC卡号*/
                            System.out.println("接收到的信息为IC只读上传的IC卡号");
                            System.out.println("指令码："+Integer.toHexString(data[0] & 0xff));
                            System.out.println("设备IP："+Integer.toString(data[1] & 0xff)+"."+Integer.toString(data[2] & 0xff)+"."+Integer.toString(data[3] & 0xff)+"."+Integer.toString(data[4] & 0xff));
                            System.out.println("机器号："+Integer.toString((data[5] & 0xff)+((data[6] & 0xff) *256)));
                            System.out.println("包序号："+Integer.toString((data[7] & 0xff)+((data[8] & 0xff) *256)));
                            for(p=10;p<14;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                CardNo16=CardNo16+ bytestr.substring(bytestr.length() -2,bytestr.length());
                            }
                            System.out.println("16进制卡号："+CardNo16);

                            cardnum=data[10] & 0xff;
                            cardnum=cardnum+(data[11] & 0xff) *256;
                            cardnum=cardnum+(data[12] & 0xff) *65536;
                            cardnum=cardnum+(data[13] & 0xff) *16777216;
                            cardno10 = 0;
                            for (j=28; j>=0; j-=4) {
                                cardno10 = cardno10<<4 | (cardnum>>>j & 0xF);
                            }
                            CardNoStr = String.format("%010d", cardno10);
                            System.out.println("10进制卡号："+CardNoStr);

                            for(p=14;p<length;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                SerialNum=SerialNum+ bytestr.substring(bytestr.length() -2,bytestr.length());
                            }
                            System.out.println("设备序列号："+SerialNum+"\n\n");

                            DisableSendAge(s,data,length,RemoteHostIP,RemotePort);         //向读卡器发确认信息，否则读卡器会连续发三次

                            if(args.length==0)
                            {
                                SendDispBeep(s,CardNoStr,RemoteHostIP,RemotePort);             //无参数时，发送显示及固定组合声音
                            }
                            else
                            {
                                SendDispSpk(s,CardNoStr,RemoteHostIP,RemotePort);             //有参数时，发送显示及TTS声音
                            }

                            //Thread.sleep(10);
                            //ReadCardInf(s,data,length,RemoteHostIP,RemotePort);             //如果是网络读写器，可以继续发指令读写

                            break;
                        case (byte)0xc3:         /*全扇区读写器收到读卡扇区内的数据*/
                            j=data[10] *48;
                            m=data[11] *48;

                            for(p=0;p<m;p++){
                                readcardbuf[j+p]=data[16+p];
                            }

                            if(data[11]+data[10]>=data[9]){        /*已完全收到所有包数据，一个数据包最多传4个扇区的数据，如果读写器设备读写扇区数大于4，数据要分2个包上传，扇区数大于8要分3个包，大与12要分4个包上传*/
                                System.out.println("接收到的信息为IC卡扇区内数据");
                                System.out.println("指令码："+Integer.toHexString(data[0] & 0xff));
                                System.out.println("设备IP："+Integer.toString(data[1] & 0xff)+"."+Integer.toString(data[2] & 0xff)+"."+Integer.toString(data[3] & 0xff)+"."+Integer.toString(data[4] & 0xff));
                                System.out.println("机器号："+Integer.toString((data[5] & 0xff)+((data[6] & 0xff) *256)));
                                System.out.println("包序号："+Integer.toString((data[7] & 0xff)+((data[8] & 0xff) *256)));
                                for(p=12;p<16;p++){
                                    bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                    CardNo16=CardNo16+ bytestr.substring(bytestr.length() -2,bytestr.length());
                                }
                                System.out.println("16进制卡号："+CardNo16);

                                SerialNum="";
                                for(int o=16+m;o<length;o++){
                                    bytestr="00"+Integer.toHexString(data[o] & 0xff);
                                    SerialNum=SerialNum+ bytestr.substring(bytestr.length() -2,bytestr.length());
                                }
                                System.out.println("设备序列号："+SerialNum+",读卡数据已全部接收完成！");

                                m=data[9] *48;
                                CardInfStr="";
                                for(p=0;p<m;p++){
                                    bytestr="00"+Integer.toHexString(readcardbuf[p] & 0xff);
                                    CardInfStr=CardInfStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
                                }
                                System.out.println("卡片内数据："+CardInfStr);
                            }
                            else{
                                SerialNum="";
                                for(int o=16+p;o<length;o++){
                                    bytestr="00"+Integer.toHexString(data[o] & 0xff);
                                    SerialNum=SerialNum+ bytestr.substring(bytestr.length() -2,bytestr.length());
                                }
                                System.out.println("设备序列号："+SerialNum+"，读卡数据还未全部接收完，需将全部数据接收完整再处理！");
                            }

                            System.out.println("\n\n");

                            break;
                        case (byte)0xc5:          /*指定区号、密码读卡返回信息*/
                            System.out.println("接收到的信息为IC卡扇区内数据");
                            System.out.println("指令码："+Integer.toHexString(data[0] & 0xff));
                            System.out.println("设备IP："+Integer.toString(data[1] & 0xff)+"."+Integer.toString(data[2] & 0xff)+"."+Integer.toString(data[3] & 0xff)+"."+Integer.toString(data[4] & 0xff));
                            System.out.println("机器号："+Integer.toString((data[5] & 0xff)+((data[6] & 0xff) *256)));
                            for(p=8;p<12;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                CardNo16=CardNo16+ bytestr.substring(bytestr.length() -2,bytestr.length());
                            }
                            System.out.println("16进制卡号："+CardNo16);
                            System.out.println("扇区数："+Integer.toHexString(data[7] & 0xff));
                            System.out.println("扇区号："+Integer.toHexString(data[12] & 0xff));
                            if(data[13]==0){
                                CardInfStr="";
                                for(p=0;p<48;p++){
                                    bytestr="00"+Integer.toHexString(data[14+p] & 0xff);
                                    CardInfStr=CardInfStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
                                }
                                System.out.println("扇区内数据："+CardInfStr);
                                System.out.println("\n\n");

                                WriteCard(s,data,length,RemoteHostIP,RemotePort);   //写卡操作

                            } else{
                                if(data[13]==12){
                                    System.out.println("卡密码认证失败！");
                                    System.out.println("\n\n");
                                }else {
                                    System.out.println("读卡失败，错误代码："+Integer.toString(data[13]));
                                    System.out.println("\n\n");
                                }
                            }
                            break;

                        case (byte)0xcD :         /*响应写卡、更改卡密码*/
                            System.out.println("设备IP："+Integer.toString(data[2] & 0xff)+"."+Integer.toString(data[3] & 0xff)+"."+Integer.toString(data[4] & 0xff)+"."+Integer.toString(data[5] & 0xff));
                            System.out.println("机器号："+Integer.toString((data[6] & 0xff)+((data[7] & 0xff) *256)));
                            for(p=9;p<13;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                CardNo16=CardNo16+ bytestr.substring(bytestr.length() -2,bytestr.length());
                            }
                            System.out.println("16进制卡号："+CardNo16);
                            System.out.println("扇区号："+Integer.toHexString(data[13] & 0xff));
                            if(data[1]==0x3A){
                                if(data[14]==0x00){
                                    System.out.println("更改卡密码成功！");
                                }else{
                                    System.out.println("更改卡密码失败，错误代码："+Integer.toString(data[14]));
                                }
                            }else{
                                if(data[1]==0x3D){
                                    if(data[14]==0x00){
                                        System.out.println("写卡成功！");
                                    }else{
                                        System.out.println("写卡失败，错误代码："+Integer.toString(data[14]));
                                    }
                                }
                            }
                            System.out.println("\n\n");
                            break;

                        case (byte)0xcf :         /*接收到IC卡离开读卡器的信息*/
                        case (byte)0xdf :         /*接收到ID卡离开读卡器的信息*/
                            System.out.println("接收到卡离开读卡器的信息");
                            System.out.println("指令码："+Integer.toHexString(data[0] & 0xff));
                            System.out.println("设备IP："+Integer.toString(data[1] & 0xff)+"."+Integer.toString(data[2] & 0xff)+"."+Integer.toString(data[3] & 0xff)+"."+Integer.toString(data[4] & 0xff));
                            System.out.println("机器号："+Integer.toString((data[5] & 0xff)+((data[6] & 0xff) *256)));
                            System.out.println("包序号："+Integer.toString((data[7] & 0xff)+((data[8] & 0xff) *256)));
                            if(data[0]==(byte)0xcf){
                                for(p=11;p<15;p++){
                                    bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                    CardNo16=CardNo16+ bytestr.substring(bytestr.length() -2,bytestr.length());
                                }
                            }else{
                                for(p=10;p<15;p++){
                                    bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                    CardNo16=CardNo16+ bytestr.substring(bytestr.length() -2,bytestr.length());
                                }
                            }
                            System.out.println("16进制卡号："+CardNo16+"\n\n");

                            DisableSendAge(s,data,length,RemoteHostIP,RemotePort);         //向读卡器发确认信息，否则读卡器会连续发三次
                            break;
                        case (byte)0xd1:         /*接收到的信息为ID读卡器上传的卡号*/
                            System.out.println("接收到的信息为ID读卡器上传的卡号");
                            System.out.println("指令码："+Integer.toHexString(data[0] & 0xff));
                            System.out.println("设备IP："+Integer.toString(data[1] & 0xff)+"."+Integer.toString(data[2] & 0xff)+"."+Integer.toString(data[3] & 0xff)+"."+Integer.toString(data[4] & 0xff));
                            System.out.println("机器号："+Integer.toString((data[5] & 0xff)+((data[6] & 0xff) *256)));
                            System.out.println("包序号："+Integer.toString((data[7] & 0xff)+((data[8] & 0xff) *256)));
                            for(p=9;p<13;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                CardNo16=CardNo16+ bytestr.substring(bytestr.length() -2,bytestr.length());
                            }
                            System.out.println("16进制卡号："+CardNo16);

                            cardnum=data[9] & 0xff;
                            cardnum=cardnum+(data[10] & 0xff) *256;
                            cardnum=cardnum+(data[11] & 0xff) *65536;
                            cardnum=cardnum+(data[12] & 0xff) *16777216;
                            cardno10 = 0;
                            for (j=28; j>=0; j-=4) {
                                cardno10 = cardno10<<4 | (cardnum>>>j & 0xF);
                            }
                            CardNoStr = String.format("%010d", cardno10);
                            System.out.println("10进制卡号："+CardNoStr);

                            for(p=14;p<length;p++){
                                bytestr="00"+Integer.toHexString(data[p] & 0xff);
                                SerialNum=SerialNum+ bytestr.substring(bytestr.length() -2,bytestr.length());
                            }
                            System.out.println("设备序列号："+SerialNum);

                            System.out.println("\n\n");
                            DisableSendAge(s,data,length,RemoteHostIP,RemotePort);             //向读卡器发确认信息，否则读卡器会连续发三次

                            if(args.length==0)
                            {
                                SendDispBeep(s,CardNoStr,RemoteHostIP,RemotePort);             //无参数时，发送显示及固定组合声音
                            }
                            else
                            {
                                SendDispTTS(s,CardNoStr,RemoteHostIP,RemotePort);             //有参数时，发送显示及TTS声音
                            }

                            break;
                        default:
                    }
                }
            }else{
                System.out.println("\n\n");
            }
        }

        s.close();                                     /**5、关闭资源*/
    }

    /*------------------------------------------------------------------------------------------------------------向读卡器发送显示文字+继电器+TTS合成语音*/
    static void SendDispTTS(DatagramSocket s,String CardNum,String RemoteHostIP,int RemotePort) throws Exception{
        //DatagramSocket s1 = new DatagramSocket();       /** 1、建立udp socket端点 */

        String DispStr="卡号:"+CardNum+"  "+GetSysDT().substring(2,19)+"        "; //将显示的文字生成字节数组
        byte[] DispBuf= DispStr.getBytes("gb2312");

        String SpeakStr="";                              //将要播报的TTS语音生成字节数组，最大不能超过126个字节
        SpeakStr="[v10]";                                //定义语音大小，最大语语音为16，可加在任何地方
        SpeakStr=SpeakStr+"欢迎您使用我们的网络读卡器";      //要播报的中文语音
        byte[] SpeakBuf= SpeakStr.getBytes("gb2312");
        int    SpeakLen=SpeakBuf.length;                //语音长度

        int SendLen=11+34+SpeakLen+4;                   //总计发送数据长度

        byte[] SendBuf1 = new byte [180];                /** 2、将要发送的数据打包 */
        SendBuf1[0]=(byte)0x5C;                          //指令码
        SendBuf1[1]=(byte)0x00;                          //机号低
        SendBuf1[2]=(byte)0x00;                          //机号高，如果高低位都为0表示任意机号
        SendBuf1[3]=(byte)0x01;                          //蜂鸣声代码
        SendBuf1[4]=(byte)0xF0;                          //继电器代码 F0表示全部继电器 F1表示1号继电器 F2表示2号继电器

        SendBuf1[5]=(byte)0x20;                          //继电器开启时长 低位
        SendBuf1[6]=(byte)0x00;                          //继电器开启时长 高位

        SendBuf1[7]=(byte)0x14;                          //显示保留时间，单位为秒，为0xFF时表示永久显示
        SendBuf1[8]=(byte)0x00;                          //在显示屏中的哪个位置开始
        SendBuf1[9]=(byte)0x22;                          //显示字符串长度 为全屏显示为 34 个字符
        SendBuf1[10]=(byte)SpeakLen;                     //语音长度

        for(int i=0;i<34;i++){                           //显示的文字信息
            SendBuf1[i+11]=DispBuf[i];
        }

        for(int i=0;i<SpeakLen;i++){                     //TTS语音播报信息
            SendBuf1[i+45]=SpeakBuf[i];
        }

        SendBuf1[10+34+SpeakLen+1]=(byte)0x55;           //固定的抗干扰后缀
        SendBuf1[10+34+SpeakLen+2]=(byte)0xaa;
        SendBuf1[10+34+SpeakLen+3]=(byte)0x66;
        SendBuf1[10+34+SpeakLen+4]=(byte)0x99;

        DatagramPacket dp1 = new DatagramPacket(SendBuf1, SendLen, InetAddress.getByName(RemoteHostIP), RemotePort);
        try {                                           /** 3、 发送数据  **/
            s.send(dp1);

            String SendInfStr="";                       //这段代码显示发送的16进制报文，正式项目可以删除
            for(int p=0;p<SendLen;p++){
                String bytestr="00"+Integer.toHexString(SendBuf1[p] & 0xff);
                SendInfStr=SendInfStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
            }
            System.out.println("SendTo ip::"+RemoteHostIP+"\nport::"+RemotePort+"\ndata::"+SendInfStr);
            System.out.println("发送文字显示及TTS语音\n\n");
        } catch (IOException e) {
            System.out.println("发送失败： ");
            e.printStackTrace();
        }
        //s1.close();                                     /**4、关闭资源*/
    }

    /*-----------------------------------------------------------------------------------------------------------向读卡器发送显示+继电器+固定组合语音*/
    static void SendDispSpk(DatagramSocket s,String CardNum,String RemoteHostIP,int RemotePort) throws Exception{
        //DatagramSocket s1 = new DatagramSocket();       /** 1、建立udp socket端点 */

        String DispStr="卡号:"+CardNum+"  "+GetSysDT().substring(2,19)+"        "; //将显示的文字生成字节数组
        byte[] DispBuf= DispStr.getBytes("gb2312");

        byte SpkLen=3;                                  //固定组合语音长度，一次最大取值21条
        byte[] SpkBuf=new byte[SpkLen];                 //固定组合语音代码缓冲，
        SpkBuf[0]=55;                                   //要播报的语音代码0
        SpkBuf[1]=41;                                   //要播报的语音代码1
        SpkBuf[2]=53;                                   //要播报的语音代码2......

        byte[] SendBuf1 = new byte [70];                 /** 2、将要发送的数据打包 */
        SendBuf1[0]=(byte)0x5B;                          //指令码
        SendBuf1[1]=(byte)0x00;                          //机号低
        SendBuf1[2]=(byte)0x00;                          //机号高，如果高低位都为0表示任意机号
        SendBuf1[3]=(byte)0x02;                          //蜂鸣声代码,取值范围参看通讯协议
        SendBuf1[4]=(byte)0xF0;                          //继电器代码 F0表示全部继电器 F1表示1号继电器 F2表示2号继电器

        SendBuf1[5]=(byte)0x20;                          //继电器开启时长 低位
        SendBuf1[6]=(byte)0x00;                          //继电器开启时长 高位

        SendBuf1[7]=(byte)0x14;                          //显示保留时间，单位为秒，为0xFF时表示永久显示
        SendBuf1[8]=(byte)0x00;                          //在显示屏中的哪个位置开始,一般取0表示首位
        SendBuf1[9]=36;                                  //显示字符串长度 为全屏显示为 36 个字符
        SendBuf1[10]=SpkLen;                             //语音长度

        for(int i=0;i<34;i++){                           //要显示的文字
            SendBuf1[11+i]=DispBuf[i];
        }

        for(int i=0;i<SpkLen;i++){                       //要播报的固定语音代码
            SendBuf1[47+i]=SpkBuf[i];
        }

        SendBuf1[47+SpkLen+0]=(byte)0x55;                //固定的抗干扰后缀
        SendBuf1[47+SpkLen+1]=(byte)0xaa;
        SendBuf1[47+SpkLen+2]=(byte)0x66;
        SendBuf1[47+SpkLen+3]=(byte)0x99;

        DatagramPacket dp1 = new DatagramPacket(SendBuf1, SendBuf1.length, InetAddress.getByName(RemoteHostIP), RemotePort);
        try {                                           /** 3、 发送数据  **/
            s.send(dp1);

            String SendInfStr="";
            for(int p=0;p<=47+SpkLen+3;p++){
                String bytestr="00"+Integer.toHexString(SendBuf1[p] & 0xff);
                SendInfStr=SendInfStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
            }
            System.out.println("SendTo ip::"+RemoteHostIP+"\nport::"+RemotePort+"\ndata::"+SendInfStr);
            System.out.println("发送文字显示+鸣器响声+继电器+固定组合语音\n\n");
        } catch (IOException e) {
            System.out.println("发送失败： ");
            e.printStackTrace();
        }
        //s1.close();                                     /**4、关闭资源*/
    }

    /*-----------------------------------------------------------------------------------------------------------向读卡器发送显示及蜂鸣器响声*/
    static void SendDispBeep(DatagramSocket s,String CardNum,String RemoteHostIP,int RemotePort) throws Exception{
        //DatagramSocket s1 = new DatagramSocket();       /** 1、建立udp socket端点 */

        String DispStr="卡号:"+CardNum+"  "+GetSysDT().substring(2,19)+"        "; //将显示的文字生成字节数组
        byte[] DispBuf= DispStr.getBytes("gb2312");

        byte[] SendBuf1 = new byte [39];                 /** 2、将要发送的数据打包 */
        SendBuf1[0]=(byte)0x5a;                          //指令码
        SendBuf1[1]=(byte)0x00;                          //机号低
        SendBuf1[2]=(byte)0x00;                          //机号高，如果高低位都为0表示任意机号
        SendBuf1[3]=(byte)0x02;                          //蜂鸣声代码
        SendBuf1[4]=(byte)0x14;                          //显示时长

        for(int i=0;i<34;i++){                           //显示文字
            SendBuf1[i+5]=DispBuf[i];
        }

        DatagramPacket dp1 = new DatagramPacket(SendBuf1, SendBuf1.length, InetAddress.getByName(RemoteHostIP), RemotePort);
        try {                                           /** 3、 发送数据  **/
            s.send(dp1);

            String SendInfStr="";
            for(int p=0;p<39;p++){
                String bytestr="00"+Integer.toHexString(SendBuf1[p] & 0xff);
                SendInfStr=SendInfStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
            }
            System.out.println("SendTo ip::"+RemoteHostIP+"\nport::"+RemotePort+"\ndata::"+SendInfStr);
            System.out.println("发送文字显示及蜂鸣器响声\n\n");
        } catch (IOException e) {
            System.out.println("发送失败： ");
            e.printStackTrace();
        }
        //s1.close();                                     /**4、关闭资源*/
    }

    /*---------------------------------------------------------------------------------------------------------------接收到读卡器信息后立即回复，防止读卡器连发三次*/
    static void DisableSendAge(DatagramSocket s,byte[] data,int length,String RemoteHostIP,int RemotePort) throws Exception{
        if(length>=8){
            //DatagramSocket s1 = new DatagramSocket();       /** 1、建立udp socket端点 */

            byte[] SendBuf1 = new byte [9];                 /** 2、将要发送的数据打包 */
            SendBuf1[0]=(byte)0x69;
            String SendInfStr="69 ";
            for(int p=1;p<9;p++){
                SendBuf1[p]=data[p];
                String bytestr="00"+Integer.toHexString(data[p] & 0xff);
                SendInfStr=SendInfStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
            }
            DatagramPacket dp1 = new DatagramPacket(SendBuf1, SendBuf1.length, InetAddress.getByName(RemoteHostIP), RemotePort);

            try {                                           /** 3、 发送数据  **/
                s.send(dp1);
                System.out.println("SendTo ip::"+RemoteHostIP+"\nport::"+RemotePort+"\ndata::"+SendInfStr);
                System.out.println("确认收到信息，防止读卡器重复发送\n\n");
            } catch (IOException e) {
                System.out.println("发送失败： ");
                e.printStackTrace();
            }
            //s1.close();                                     /**4、关闭资源*/
        }
    }

    /*------------------------------------------------------------------------------------------------------------更改读卡器的IP、网关、掩码、服务器ip、端口等*/
    static void SetNetworkPara(DatagramSocket s,byte[] data,int length,String RemoteHostIP,int RemotePort) throws Exception{
        if(length>=38){
            //DatagramSocket s1 = new DatagramSocket();       /** 1、建立udp socket端点 */

            byte[] SendBuf1 = new byte [42];                /** 2、将要发送的数据打包 */
            SendBuf1[0]=(byte)0xF9;

            SendBuf1[1]=data[1];    //读卡器ip,如需修改设正确值
            SendBuf1[2]=data[2];
            SendBuf1[3]=data[3];
            SendBuf1[4]=data[4];

            SendBuf1[5]=data[5];     //读卡器子网掩码,如需修改设正确值
            SendBuf1[6]=data[6];
            SendBuf1[7]=data[7];
            SendBuf1[8]=data[8];

            SendBuf1[9]=(byte)0xff;   //data[23];     //读卡器远程服务器IP,,255.255.255.255表示广播方式，如需修改设正确值
            SendBuf1[10]=(byte)0xff;  //data[24];
            SendBuf1[11]=(byte)0xff;  //data[25];
            SendBuf1[12]=(byte)0xff;  //data[26];

            SendBuf1[13]=data[27];  //读卡器远程服务器IP MAC，取值FF-FF-FF-FF-FF-FF 表示自动搜索MAC
            SendBuf1[14]=data[28];
            SendBuf1[15]=data[29];
            SendBuf1[16]=data[30];
            SendBuf1[17]=data[31];
            SendBuf1[18]=data[32];

            SendBuf1[19]=data[13];  //读卡器网关IP,如需修改设正确值
            SendBuf1[20]=data[14];
            SendBuf1[21]=data[15];
            SendBuf1[22]=data[16];

            SendBuf1[23]=data[17];   //读卡器网关MAC，取值FF-FF-FF-FF-FF-FF 表示自动搜索MAC
            SendBuf1[24]=data[18];
            SendBuf1[25]=data[19];
            SendBuf1[26]=data[20];
            SendBuf1[27]=data[21];
            SendBuf1[28]=data[22];

            SendBuf1[29]=data[11];  //机号,如需修改设正确值
            SendBuf1[30]=data[12];

            SendBuf1[31]=data[9];   //通讯端口,如需修改设正确值
            SendBuf1[32]=data[10];

            SendBuf1[33]=data[35];  //机器序列号，每台机唯一，不可更改
            SendBuf1[34]=data[36];
            SendBuf1[35]=data[37];
            SendBuf1[36]=data[38];

            byte Funcode;
            Funcode=1;                    //0    刷卡时不发声        1   刷卡时发声
            Funcode=(byte)(Funcode+2);    //+2  远程电脑MAC自动搜索  +4   网关MAC自动搜索
            Funcode=(byte)(Funcode+8);    //+8  DHCP自动获得IP地址  +0   指定IP
            Funcode=(byte)(Funcode+0);    //+16 卡离开感应区发信息   +0   卡离开感应区不发信息
            Funcode=(byte)(Funcode+32*0); //卡在感应区是否重发信息    *0不重发  *1隔1秒重发  *2隔2秒重发  *3隔5秒重发  *4隔10秒重发

            SendBuf1[37]=Funcode;

            SendBuf1[38]=(byte)0x55;  //4字节固定后缀
            SendBuf1[39]=(byte)0xaa;
            SendBuf1[40]=(byte)0x66;
            SendBuf1[41]=(byte)0x99;

            DatagramPacket dp1 = new DatagramPacket(SendBuf1, SendBuf1.length, InetAddress.getByName(RemoteHostIP), RemotePort);
            try {                                           /** 3、 发送数据  **/
                s.send(dp1);

                String SendInfStr="";      //将发送的信息显示
                for(int p=0;p<42;p++){
                    String bytestr="00"+Integer.toHexString(SendBuf1[p] & 0xff);
                    SendInfStr=SendInfStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
                }
                System.out.println("SendTo ip::"+RemoteHostIP+"\nport::"+RemotePort+"\ndata::"+SendInfStr);
                System.out.println("更改设备的网络参数\n\n");
            } catch (IOException e) {
                System.out.println("发送失败： ");
                e.printStackTrace();
            }
            //s1.close();                                     /**4、关闭资源*/
        }
    }

    /*---------------------------------------------------------------------------------------------------------------发指令到读写器读取指定扇区内数据*/
    static void ReadCardInf(DatagramSocket s,byte[] data,int length,String RemoteHostIP,int RemotePort) throws Exception{
        if(length>=8){
            //DatagramSocket s1 = new DatagramSocket();       /** 1、建立udp socket端点 */

            byte[] SendBuf1 = new byte [16];                /** 2、将要发送的数据打包 */
            SendBuf1[0]=(byte)0x3B;

            SendBuf1[1]=data[5];          //机号低
            SendBuf1[2]=data[6];          //机号高，如高低都为0表示任意机号

            SendBuf1[3]=(byte)0x01;       //扇区个数

            SendBuf1[4]=data[10];         //要操作的卡号，如4个字节都取0表示可操作任意卡
            SendBuf1[5]=data[11];
            SendBuf1[6]=data[12];
            SendBuf1[7]=data[13];

            SendBuf1[8]=(byte)0x08;        //要读取的扇区号
            SendBuf1[9]=(byte)0x00;        //取值0表示以A密码认证，取值1表示以B密码认证

            SendBuf1[10]=(byte)0xFF;       //6字节的卡片认证密码
            SendBuf1[11]=(byte)0xFF;
            SendBuf1[12]=(byte)0xFF;
            SendBuf1[13]=(byte)0xFF;
            SendBuf1[14]=(byte)0xFF;
            SendBuf1[15]=(byte)0xFF;

            DatagramPacket dp1 = new DatagramPacket(SendBuf1, SendBuf1.length, InetAddress.getByName(RemoteHostIP), RemotePort);
            try {                                           /** 3、 发送数据  **/
                s.send(dp1);

                String SendInfStr="";
                for(int p=0;p<16;p++){
                    String bytestr="00"+Integer.toHexString(SendBuf1[p] & 0xff);
                    SendInfStr=SendInfStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
                }
                System.out.println("SendTo ip::"+RemoteHostIP+"\nport::"+RemotePort+"\ndata::"+SendInfStr);
                System.out.println("向读写器发送读取扇区信息的指令\n\n");
            } catch (IOException e) {
                System.out.println("发送失败： ");
                e.printStackTrace();
            }
            //s1.close();                                     /**4、关闭资源*/
        }
    }

    /*---------------------------------------------------------------------------------------------------------------发指令写数据到卡内*/
    static void WriteCard(DatagramSocket s,byte[] data,int length,String RemoteHostIP,int RemotePort) throws Exception{
        if(length>=62){
            //DatagramSocket s1 = new DatagramSocket();       /** 1、建立udp socket端点 */

            byte[] SendBuf1 = new byte [68];                /** 2、将要发送的数据打包 */
            SendBuf1[0]=(byte)0x3D;        //指定扇区写卡指令

            SendBuf1[1]=data[5];           //机号低
            SendBuf1[2]=data[6];           //机号高，如高低都为0表示任意机号

            SendBuf1[3]=(byte)0x01;        //扇区个数

            SendBuf1[4]=data[8];           //要操作的卡号，如4个字节都取0表示可操作任意卡
            SendBuf1[5]=data[9];
            SendBuf1[6]=data[10];
            SendBuf1[7]=data[11];

            SendBuf1[8]=(byte)0x08;        //要操作的扇区号
            SendBuf1[9]=(byte)0x00;        //取值0表示以A密码认证，取值1表示以B密码认证

            SendBuf1[10]=(byte)0xFF;       //6字节的卡片认证密码
            SendBuf1[11]=(byte)0xFF;
            SendBuf1[12]=(byte)0xFF;
            SendBuf1[13]=(byte)0xFF;
            SendBuf1[14]=(byte)0xFF;
            SendBuf1[15]=(byte)0xFF;

            for(int p=0;p<48;p++){         //48个字节的写入信息，一定要满48字节
                SendBuf1[16+p]=data[14+p]; //这里表示将读出的信息重新写入，如要写新的数据将数据写入这段缓冲
            }

            SendBuf1[64]=(byte)0x55;       //固定的抗干扰后缀
            SendBuf1[65]=(byte)0xAA;
            SendBuf1[66]=(byte)0x66;
            SendBuf1[67]=(byte)0x99;

            DatagramPacket dp1 = new DatagramPacket(SendBuf1, SendBuf1.length, InetAddress.getByName(RemoteHostIP), RemotePort);
            try {                                           /** 3、 发送数据  **/
                s.send(dp1);

                String SendInfStr="";
                for(int p=0;p<68;p++){
                    String bytestr="00"+Integer.toHexString(SendBuf1[p] & 0xff);
                    SendInfStr=SendInfStr+ bytestr.substring(bytestr.length() -2,bytestr.length())+" ";
                }
                System.out.println("SendTo ip::"+RemoteHostIP+"\nport::"+RemotePort+"\ndata::"+SendInfStr);
                System.out.println("向读写器发送写扇区信息的指令\n\n");
            } catch (IOException e) {
                System.out.println("发送失败： ");
                e.printStackTrace();
            }
            //s1.close();                                     /**4、关闭资源*/
        }
    }

    /*---------------------------------------------------------------------------------------------------------判断字符串是不是一个日期时间格式*/
    static boolean IsDateTime(String inputstr) {
        Date date=null;
        SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try{
            date=formatter.parse(inputstr);
            return true;
        }catch (Exception e) {
            return false;
        }
    }
    /*--------------------------------------------------------------------------------------------------------------------取电脑系统日期时间*/
    static String GetSysDT() {
        Date date=new Date();
        SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String TimeStr=formatter.format(date);
        return TimeStr;
    }
    /*----------------------------------------------------------------------------------------------------------------------------取电脑IP*/
    public static String getIP(){
        Enumeration<NetworkInterface> netInterfaces;
        ArrayList<String> IpAddList = new ArrayList<String>();
        try {
            netInterfaces = NetworkInterface.getNetworkInterfaces();    // 拿到所有网卡
            InetAddress ip;
            while (netInterfaces.hasMoreElements()) {
                NetworkInterface ni = netInterfaces.nextElement();
                Enumeration<InetAddress> addresses = ni.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    ip = addresses.nextElement();
                    if (!ip.isLoopbackAddress() && ip.getHostAddress().indexOf(':') == -1) {
                        IpAddList.add(ip.getHostAddress());
                        System.out.println((IpAddList.size()-1)+""+ " " +ni.getName() + " "+ ip.getHostAddress());
                    }
                }
            }
        } catch (Exception e) {

        }

        if(IpAddList.isEmpty()){
            return "127.0.0.1";
        }else{
            return IpAddList.get(1);    //如有多张网卡，请选择与设备相连的网卡，否则无法与设备正常通讯
        }
    }

}